#include <Arduino.h>
#include <esp_heap_caps.h>
#include "spiram_psram.h"

#include "motor/motor.h"
#include "keyboard/keyboard.h"
#include "esp32-hal.h"
#include <TFT_eSPI.h>

#include "lvgl.h"
#include "lv_port_indev.h"
#include "appdata/app_data.h"

#include "ui/ui.h"

TaskHandle_t handleTasktft;
TaskHandle_t handleTaskMotor;
TaskHandle_t handleTaskKeyBoard;
TaskHandle_t handleTasktouch_id;
TaskHandle_t handleTaskAudio;
TaskHandle_t handleTasksky;
// 定义分辨率
static const uint16_t screenWidth = 240;
static const uint16_t screenHeight = 240;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t *disp_draw_buf;
static lv_disp_drv_t disp_drv;

TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */

/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);
    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);
    tft.pushColors((uint16_t *)&color_p->full, w * h, true);
    tft.endWrite();
    lv_disp_flush_ready(disp);
}
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
   // Stop further decoding as image is running off bottom of screen
  if ( y >= tft.height() ) return 0;

  // This function will clip the image block rendering automatically at the TFT boundaries
  tft.pushImage(x, y, w, h, bitmap);

  // This might work instead if you adapt the sketch to use the Adafruit_GFX library
  // tft.drawRGBBitmap(x, y, bitmap, w, h);

  // 返回1解码下一个块
  return 1;
}

void tft_init(void *pvParameters)
{

    pinMode(4, OUTPUT); // 屏幕背光
    digitalWrite(4, HIGH);
    tft.begin();        /* TFT init TFT初始化*/
    tft.setRotation(0); /* Landscape orientation, flipped 设置方向*/
                        /*一个静态或全局变量来存储缓冲区*/
                        // The jpeg image can be scaled by a factor of 1, 2, 4, or 8
    TJpgDec.setJpgScale(1);

    // The byte order can be swapped (set true for TFT_eSPI)
    TJpgDec.setSwapBytes(true);

    // The decoder must be given the exact name of the rendering function above
    TJpgDec.setCallback(tft_output);
    lv_init();
    void *ptrVal = NULL;
    ptrVal = heap_caps_malloc(sizeof(lv_color_t) * screenWidth * screenHeight, MALLOC_CAP_SPIRAM);
    lv_color_t *disp_draw_buf1 = (lv_color_t *)ptrVal;
    void *ptrVal1 = NULL;
    ptrVal1 = heap_caps_malloc(sizeof(lv_color_t) * screenWidth * screenHeight, MALLOC_CAP_SPIRAM);
    lv_color_t *disp_draw_buf2 = (lv_color_t *)ptrVal1;

    if (!disp_draw_buf1 || !disp_draw_buf2)
    {
        Serial.println("LVGL disp_draw_buf allocate failed!");
    }
    else
    {
        lv_disp_draw_buf_init(&draw_buf, disp_draw_buf1, disp_draw_buf2, screenWidth * screenHeight);
        lv_disp_drv_init(&disp_drv);
        disp_drv.hor_res = screenWidth;
        disp_drv.ver_res = screenHeight;
        disp_drv.flush_cb = my_disp_flush;
        disp_drv.draw_buf = &draw_buf;
        disp_drv.full_refresh = 1;
        disp_drv.direct_mode = 1;
        lv_disp_drv_register(&disp_drv);
    }
    lv_port_indev_init();
    ui_init();
    while (true)
    {
        lv_timer_handler();
        vTaskDelay(LV_DISP_DEF_REFR_PERIOD);
    }
}

void setup()
{

    setCpuFrequencyMhz(240);
    Serial.begin(115200);
#if ARDUINO_USB_CDC_ON_BOOT
    Serial0.begin(115200);
#endif

    seriall_begin();
    xTaskCreatePinnedToCore(
        keyboard_init,
        "keyboard_init",
        6144, // 栈大小
        NULL,
        14, // 任务优先级, with 3 (configMAX_PRIORITIES - 1) 是最高的，0是最低的.
        &handleTaskKeyBoard,
        0);

    pinMode(EN_12V, OUTPUT); // 电机供电开
    digitalWrite(EN_12V, HIGH);
    //  开启多线程

    xTaskCreatePinnedToCore(
        motor_init,
        "motor_init",
        6144, // 栈大小
        NULL,
        24, // 任务优先级, with 3 (configMAX_PRIORITIES - 1) 是最高的，0是最低的.
        &handleTaskMotor,
        0);

    xTaskCreatePinnedToCore(
        tft_init,
        "tft_init",
        1024 * 12, // 栈大小
        NULL,
        24, // 任务优先级, with 3 (configMAX_PRIORITIES - 1) 是最高的，0是最低的.
        &handleTasktft,
        1);
#if SmartKB32_v2
    xTaskCreatePinnedToCore(
        touch_id_init,
        "touch_id_init",
        4096, // 栈大小
        NULL,
        1, // 任务优先级, with 3 (configMAX_PRIORITIES - 1) 是最高的，0是最低的.
        &handleTasktouch_id,
        0);
    sd_begin();
    // xTaskCreatePinnedToCore(
    //     Audio_init,
    //     "Audio_init",
    //     10240, // 栈大小
    //     NULL,
    //     3, // 任务优先级, with 3 (configMAX_PRIORITIES - 1) 是最高的，0是最低的.
    //     &handleTaskAudio,
    //     0);
#endif
    Serial.printf("Deafult free size: %d\r\n", heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
    Serial.printf("PSRAM free size: %d\r\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
}
bool old_sw0 = 1;
void loop()
{

    bool sw0 = digitalRead(0);
    if (sw0 != old_sw0)
    {
        if (dial_or_lvgl == KNOB_DIAL)
        {
            sw0 ? dict_release() : dict_press();
        }
    }
    old_sw0 = sw0;
    delay(30);
}
